<template>
<div ref="right" class="right-area">
  <div v-for="node in nodes" v-if="nodes.length" :id="node.id" :key="node.id" ref="nodes" class="node" :class="node.className" :style="node.style" @dblclick="editNodeText(node)">
    {{ node.text }}</div>
  <!-- <el-button class="demo" type="primary" @click="getAllNodes">获取所有节点</el-button> -->
  <!-- <el-button class="demo" type="primary" @click="getAlledges">获取所有连接</el-button> -->
  <div class="demo">
    <Button
        type="primary"
        style="margin:5px"
        @click="commitDatas"
      >保存</Button>
    <Button
        type="primary"
        style="margin:5px"
        @click="clearAll"
      >清除</Button>
    <Button
        type="primary"
        style="margin:5px"
        @click="reload"
      >重现</Button>
    <div style="width:300pxl;float:right;border:1px solid #333;">
      <Form ref="flow" :model="flowItem" :label-width="40">
        <div class="formLogin-title" style="text-align:center; border-bottom: 1px solid #333;">
          <h3>流程属性</h3>
        </div>
        <Form-item label="名称" prop="Name">
          <Input
              v-model="flowItem.Name"
              type="text"
              placeholder="流程名称"
            >
          </Input>
        </Form-item>
        <Form-item label="业务表名称" prop="Busyname">
          <Input
              v-model="flowItem.Busyname"
              placeholder="请输入"
            ></Input>
        </Form-item>
        <Form-item label="说明" prop="Remark">
          <Input
              v-model="flowItem.Remark"
              type="textarea"
              placeholder="流程说明"
            >
          </Input>
        </Form-item>
      </Form>
    </div>
  </div>
  <Modal v-model="flowVisible" title="流程信息" :mask-closable="false" class="editm" @on-ok="asyncOK" @on-cancel="asynCancel">
    <Form ref="flowForm" :model="flowItem" :label-width="80" :rules="ruleFlow">
      <Form-item label="流程标识" prop="Id">
        <Input
            v-model="flowItem.Id"
            placeholder="流程标识"
            disabled
            @on-enter="asyncOK()"
          ></Input>
      </Form-item>
      <Form-item label="流程名称" prop="Name">
        <Input
            v-model="flowItem.Name"
            placeholder="请输入"
            @on-enter="asyncOK()"
          ></Input>
      </Form-item>
      <Form-item label="业务表名称" prop="Busyname" required>
        <Input
            v-model="flowItem.Busyname"
            placeholder="请输入"
            @on-enter="asyncOK()"
          ></Input>
      </Form-item>
      <Form-item label="说明" prop="Remark">
        <Input
            v-model="flowItem.Remark"
            type="textarea"
            :autosize="{minRows: 2,maxRows: 5}"
            placeholder="请输入..."
          >
        </Input>
      </Form-item>
    </Form>
  </Modal>
  <Modal v-model="connectVisible" :title="`请${dialogTitle}`">
    <Form ref="connectForm" :model="formConnect" :label-width="80">
      <Form-item label="触发事件" prop="Event" required>
        <Select
            v-model="formConnect.Event"
            placeholder="请选择"
          >
            <Option 
              v-for="item in eventList" 
              :key="item.Id" 
              :value="item.Id"
            >{{ item.Name }}</Option>
          </Select>
      </Form-item>
      <Form-item label="动作" prop="Action" required>
        <Select
            v-model="formConnect.Action"
            placeholder="请选择"
          >
            <Option 
              v-for="item in actionList" 
              :key="item.Id" 
              :value="item.Id"
            >{{ item.Name }}</Option>
          </Select>
      </Form-item>
    </Form>
    <div slot="footer" class="dialog-footer">
      <Button
          v-show="dialogTitle.startsWith('编辑')"
          type="error"
          @click="remove"
        >
          删除{{ dialogTitle.substr(2,2) }}
        </Button>
      <Button @click="closeDialog">取 消</Button>
      <Button
          type="primary"
          @click="summit"
        >确 定</Button>
    </div>
  </Modal>
  <Modal v-model="stateVisible" :title="`请${dialogTitle}`">
    <Form ref="stateForm" :model="formState" :label-width="80" :rules="ruleState">
      <Form-item label="节点名称" prop="Name" required>
        <Input
            v-model="formState.Name"
            placeholder="请输入"
            @on-enter="asyncOK()"
          ></Input>
      </Form-item>
      <Form-item v-if="dialogType==='task' || dialogType === 'dispatch' || dialogType === 'distributen ' " label="角色" prop="Role" required>
        <Select
            v-model="formState.Role"
            placeholder="请选择"
          >
            <Option 
              v-for="item in roleList" 
              :key="item.Id" 
              :value="item.Id"
            >{{ item.Name }}</Option>
          </Select>
      </Form-item>
      <Form-item label="说明" prop="Remark">
        <Input
            v-model="formState.Remark"
            type="textarea"
            :autosize="{minRows: 2,maxRows: 5}"
            placeholder="请输入..."
          >
        </Input>
      </Form-item>
    </Form>
    <div slot="footer" class="dialog-footer">
      <Button
          v-show="dialogTitle.startsWith('编辑')"
          type="error"
          @click="remove"
        >
          删除{{ dialogTitle.substr(2,2) }}
        </Button>
      <Button @click="closeDialog">取 消</Button>
      <Button
          type="primary"
          @click="summit"
        >确 定</Button>
    </div>
  </Modal>
</div>
</template>

<script>
import { mapMutations, mapGetters, mapState } from 'vuex';
const DynamicAnchors = ['Left', 'Right', 'Top', 'Bottom'];
const sourceAnchors = ['RightMiddle', 'BottomCenter'];
const targetAnchors = ['LeftMiddle', 'TopCenter'];

const connectorStyle = {
  stroke: '#7AB02C',
  strokeWidth: 2,
  joinstyle: 'round'
};

const connectorHoverStyle = {
  stroke: '#5c96bc',
  strokeWidth: 3
};

const endpointStyle = {
  fill: 'transparent',
  stroke: '#7AB02C',
  radius: 7,
  strokeWidth: 1
};

const endpointHoverStyle = {
  fill: '#5c96bc',
  stroke: '#5c96bc',
  radius: 7,
  strokeWidth: 1
};

const anEndpoint = {
  connector: 'Flowchart',
  endpoint: 'Dot',
  isSource: true,
  isTarget: true,
  paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  connectorStyle: connectorStyle,
  connectorHoverStyle: connectorHoverStyle,
  maxConnections: 10
};
const sourceEndpoint = {
  connector: 'Flowchart',
  endpoint: 'Dot',
  isSource: true,
  // isTarget: true,
  paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  connectorStyle: connectorStyle,
  connectorHoverStyle: connectorHoverStyle,
  dragOptions: {},
  maxConnections: -1
};
const targetEndpoint = {
  connector: 'Flowchart',
  endpoint: 'Dot',
  // isSource: true,
  isTarget: true,
  // paintStyle: endpointStyle,
  hoverPaintStyle: endpointHoverStyle,
  dropOptions: {
    hoverClass: 'hover',
    activeClass: 'active'
  },
  // connectorStyle: connectorStyle,
  // connectorHoverStyle: connectorHoverStyle,
  maxConnections: -1
};
const Common = {
  // anchor: DynamicAnchors,
  connector: 'State Machine ',
  endpoint: 'Dot',
  paintStyle: connectorStyle,
  hoverPaintStyle: connectorHoverStyle,
  endpointStyle,
  endpointHoverStyle
  // maxConnections: 1,
};

export default {
  name: 'RightArea',
  props: {
    jsp: {
      type: Object
    },
    flowdata: {
      type: Object
    },
    pos: {
      type: Array
    }
  },
  data () {
    return {
      datas: null,
      connectVisible: false,
      stateVisible: false,
      flowVisible: false,
      dialogTitle: '',
      dialogText: '',
      dialogType: '', // 编辑属性
      nodes: [],
      roleList: [],
      actionList: [],
      eventList: [],
      // flow数据编辑表单
      flowItem: {
        Name: '',
        Busyname: '',
        Id: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      // flow数据编辑表单校验
      ruleFlow: {
        Name: [
          {
            required: true,
            message: '名称不能为空',
            trigger: 'blur'
          }
        ],
        Busyname: [
          {
            required: true,
            message: '业务名称不能为空',
            trigger: 'blur'
          }
        ]
      },
      // State数据编辑表单
      formState: {
        Name: '',
        Id: '',
        Flow: '',
        Role: '',
        Type: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      // State数据编辑表单校验
      ruleState: {
        Name: [
          {
            required: true,
            message: '名称不能为空',
            trigger: 'blur'
          }
        ]
      },
      // Connect数据编辑表单
      formConnect: {
        Event: '',
        Action: '',
        Id: '',
        Flow: '',
        Role: '',
        Type: '',
        Organization: '',
        OrgName: '',
        Remark: ''
      },
      info: null, // 连接信息
      rjsp: this.$jsplumb.getInstance({
        ConnectionOverlays: [
          [
            'Arrow',
            {
              location: 1,
              id: 'arrow',
              width: 11,
              length: 11
            }
          ],
          [
            'Label',
            {
              location: 0.3,
              id: 'label',
              cssClass: 'jsp-label',
              events: {
                dblclick: this.editLabelText
              }
            }
          ]
        ]
      })
    };
  },
  computed: {
    ...mapState(['isLogin', 'captchaUrl', 'cptId', 'msg'])
  },
  mounted () {
    this.getRole();
    this.getAction();
    this.getEvent();
    this.init();
  },
  methods: {
    init () {
      this.jsp.droppable(this.$refs.right, {
        drop: this._jspDrop
      });
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop);
      this._fetchData();
      setTimeout(() => {
        this.saveDatas();
      }, 1000);
    },
    getRole () {
      this.spinShow = true;
      this.$api.getRoleList().then(res => {
        if (!res.error) {
          this.roleList = res.Data;
        } else {
          this.$Message.error(res.message);
        }
      });
    },
    getAction () {
      this.spinShow = true;
      this.$api.getAction().then(res => {
        if (!res.error) {
          this.actionList = res.Data;
        } else {
          this.$Message.error(res.message);
        }
      });
    },
    getEvent () {
      this.spinShow = true;
      this.$api.getEvent().then(res => {
        if (!res.error) {
          this.eventList = res.Data;
        } else {
          this.$Message.error(res.message);
        }
      });
    },
    _jspDrop (info) {
      // if (this.flowItem.Id) {
      this.info = info;
      this.dialogType = info.drag.el.getAttribute('typeid');
      this.openDialog('输入新建节点的文本');
      // }
    },
    _jspBeforeDrop (info) {
      info.targetId = info.dropEndpoint.elementId;
      info.uuids = [
        info.connection.endpoints[0].getUuid(),
        info.dropEndpoint.getUuid()
      ];
      let connections = this.rjsp.getConnections({
        source: info.sourceId,
        target: info.targetId
      });
      if (connections.length === 0) {
        // 检察是否已经建立过连接
        this.info = info;
        this.openDialog('输入新建连接的文本');
      } else {
        this.editLabelText(connections[0].getOverlay('label'));
      }
    },
    openDialog (title) {
      this.dialogTitle = title;
      if (this.dialogTitle === '输入新建节点的文本') {
        this.stateVisible = true;
      } else if (this.dialogTitle === '编辑节点的文本') {
        this.stateVisible = true;
      } else if (this.dialogTitle === '输入新建连接的文本') {
        this.connectVisible = true;
      } else if (this.dialogTitle === '编辑连接的文本') {
        this.connectVisible = true;
      }
      // this.closeDialog()
    },
    closeDialog () {
      this.$refs.connectForm.resetFields();
      this.$refs.stateForm.resetFields();
      this.connectVisible = false;
      this.stateVisible = false;
    },
    editNodeText (info) {
      this.dialogText = info.text;
      this.dialogType = info.className;
      this.formState.Name = info.text;
      this.formState.Id = info.id;
      this.formState.Role = info.role;
      this.info = info;
      this.openDialog('编辑节点的文本');
    },
    editLabelText (info) {
      this.dialogText = info.labelText;
      this.info = info.component;
      console.log(info);
      this.formConnect.Action = info.component.scope;
      this.formConnect.Event = this.getEventId(info.labelText);
      this.openDialog('编辑连接的文本');
    },
    summit () {
      if (this.dialogTitle === '输入新建节点的文本') {
        this.nodes.push(this._createNode(this.info.drag.el, this.info.drop.el));
        this.$nextTick(_ =>
          this._initNode(this.$refs.nodes[this.nodes.length - 1])
        );
      } else if (this.dialogTitle === '编辑节点的文本') {
        this.info.text = this.formState.Name;
        this.info.role = this.formState.Role;
      } else if (this.dialogTitle === '输入新建连接的文本') {
        this._addEdge(this.info);
      } else if (this.dialogTitle === '编辑连接的文本') {
        let labelText = this.getEventName(this.formConnect.Event);
        this.info.scope = this.formConnect.Action;
        this.$nextTick(_ => this.info.getOverlay('label').setLabel(labelText));
      }
      this.closeDialog();
    },
    saveDatas () {
      this.datas = {
        nodes: this.nodes.map((node, index) => {
          node.style = this._getStyle(this.$refs.nodes[index]);
          return node;
        }),
        edges: this.rjsp.getAllConnections().map(connection => {
          return {
            source: connection.sourceId,
            target: connection.targetId,
            uuids: [
              connection.endpoints[0].getUuid(),
              connection.endpoints[1].getUuid()
            ],
            event: this.getEventId(connection.getOverlay('label').labelText),
            action: connection.scope,
            labelText: connection.getOverlay('label').labelText
          };
        }),
        flow: this.flowItem
      };
    },
    commitDatas () {
      this.saveDatas();
      console.log(this.datas);
      if (this.flowdata.edit) {
        this.$api.UpdateFlow(this.datas).then(
          res => {
            if (!res.error) {
              this.$Message.success(res.message);
              this.$router.push({
                name: '流程管理'
              });
            } else {
              this.$Message.error(res.message, 4);
            }
          },
          err => {
            if (err) {
              this.$Message.error(err, 4);
            }
          }
        );
      } else {
        this.$api.AddFlow(this.datas).then(
          res => {
            if (!res.error) {
              this.$Message.success(res.message);
              this.$router.push({
                name: '流程管理'
              });
            } else {
              this.$Message.error(res.message, 4);
            }
          },
          err => {
            if (err) {
              this.$Message.error(err, 4);
            }
          }
        );
      }
    },
    _getStyle (node) {
      let container = this.$refs.right.getBoundingClientRect();
      let rect = node.getBoundingClientRect();
      return {
        left: rect.left - container.left - node.clientLeft + 'px',
        top: rect.top - container.top - node.clientTop + 'px'
        // lineHeight: node.clientHeight + 'px'
      };
    },
    newData () {
      this.clearAll();
      // this.flowItem = {}
      // this.flowItem.Status = 1
      this.$refs.flowForm.resetFields();
      this.flowItem.Id = this.$util.uuid();
      this.flowVisible = true;
      this.jsp.droppable(this.$refs.right, {
        drop: this._jspDrop
      });
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop);
    },
    asyncOK () {
      this.$refs['flowForm'].validate(valid => {
        if (valid) {
          this.flowVisible = false;
        } else {
          this.$Message.error('表单验证失败!');
          setTimeout(() => {
            this.flowVisible = true;
          }, 500);
        }
      });
    },
    asynCancel () {
      this.flowVisible = false;
      this.$router.push({
        name: '流程管理'
      });
    },
    clearAll () {
      this.rjsp.reset();
      this.nodes = [];
    },
    reload () {
      this.clearAll();
      this.rjsp.bind('beforeDrop', this._jspBeforeDrop);
      this.nodes = this.datas.nodes;
      this.$nextTick(_ => {
        this._initNodes(this.$refs.nodes);
        this._initEdges(this.datas.edges);
      });
    },
    remove () {
      if (this.dialogTitle === '编辑节点的文本') {
        this._removeNode(this.info);
      } else if (this.dialogTitle === '编辑连接的文本') {
        this._removeEgde(this.info);
      }
      this.closeDialog();
    },
    _removeNode (node) {
      this.rjsp.deleteConnectionsForElement(node.id);
      this.saveDatas();
      this.datas.nodes.splice(
        this.datas.nodes.findIndex(n => n.id === node.id),
        1
      );
      this.reload();
    },
    _removeEgde (egde) {
      this.rjsp.deleteConnection(egde);
      this.saveDatas();
    },
    _addEdge (info) {
      let labelText = this.getEventName(this.formConnect.Event);
      let c = this.rjsp.connect(
        {
          uuids: info.uuids,
          // source: info.sourceId,
          // target: info.targetId,
          // scope: this.formConnect.Action,
          editable: true
        },
        Common
      );
      c.scope = this.formConnect.Action;
      this.$nextTick(_ => c.getOverlay('label').setLabel(labelText));
    },
    getEventName (id) {
      let n = '';
      for (let e in this.eventList) {
        if (this.eventList[e].Id === id) {
          n = this.eventList[e].Name;
        }
      }
      return n;
    },
    getEventId (name) {
      let n = '';
      for (let e in this.eventList) {
        if (this.eventList[e].Name === name) {
          n = this.eventList[e].Id;
        }
      }
      return n;
    },
    _createNode (dragEl, dropEl) {
      let rect = dropEl.getBoundingClientRect();
      return {
        className: dragEl.getAttribute('typeid'),
        id: this.$util.uuid(),
        text: this.formState.Name,
        role: this.formState.Role,
        style: {
          left: this.pos[0] - rect.left - dragEl.clientLeft + 'px',
          top: this.pos[1] - rect.top - dragEl.clientTop + 'px',
          lineHeight: dragEl.clientHeight + 'px'
        }
      };
    },
    _initNode (node) {
      this.rjsp.draggable(node, {
        constrain: true
      });
      // DynamicAnchors.map(anchor => this.rjsp.addEndpoint(node, anEndpoint, {
      //   anchor
      // }))
      // console.log(node.id)
      for (let i = 0; i < sourceAnchors.length; i++) {
        let sourceUUID = node.id + '$' + sourceAnchors[i];
        let el = this.rjsp.addEndpoint(node.id, sourceEndpoint, {
          anchor: sourceAnchors[i],
          uuid: sourceUUID
        });
      }
      for (let j = 0; j < targetAnchors.length; j++) {
        let targetUUID = node.id + '$' + targetAnchors[j];
        let el = this.rjsp.addEndpoint(node.id, targetEndpoint, {
          anchor: targetAnchors[j],
          uuid: targetUUID
        });
      }
      this.rjsp.makeTarget(node, targetEndpoint);
    },
    _initNodes (nodes) {
      nodes.map(node => this._initNode(node));
    },
    _initEdges (edges) {
      edges.map(edge => {
        let c = this.rjsp.connect(
          {
            uuids: edge.uuids,
            editable: true
          },
          Common
        );
        console.log(c);
        c.scope = edge.action;
        this.$nextTick(_ => c.getOverlay('label').setLabel(edge.labelText));
      });
    },
    _fetchData () {
      // this.$http.get('/api/data').then(res => {
      let data = this.flowdata;
      if (data.edit) {
        this.flowItem = data.flow;
        this.nodes = data.nodes;
        this.$nextTick(_ => {
          this._initNodes(this.$refs.nodes);
          this._initEdges(data.edges);
        });
      } else {
        this.newData();
      }
    }
  }
};
</script>

<style lang="css" scoped>
/* .right-area {
  position: relative;
} */

.demo {
  position: fixed;
  /* width: 74%; */
  top: 100px;
  right: 50px;
}

.node {
  /* padding: 0 10px; */
  /* overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap; */
  font-size: 14px;
  line-height: 2.5em;
  text-align: center;
  cursor: pointer;
  background-color: #5cadff;
  padding-left: 10px;
  padding-right: 10px;

}

.start,
.end {
  position: absolute;
  width: auto;
  height: 2.5em;
  border: 1px solid #333;
  /* border-radius: 50%; */
  border-radius: 5px;
  box-sizing: border-box;
}

.task,
.auto,
.fork,
.join,
.subflow, .dispatch, .distribute {
  position: absolute;
  width: auto;
  height: 2.5em;
  border: 1px solid #333;
  border-radius: 5px;
  box-sizing: border-box;
}

.start:before {
  content: "\f29f";
  font-family: ionicons;
  /* font-size: 1em; */
}

.end:before {
  content: "\f29e";
  font-family: ionicons;
  /* font-size: 1em; */
}

.task:before {
  content: "\f213";
  font-family: ionicons;
  /* font-size: 1em; */
}

.auto:before {
  content: "\f13e";
  font-family: ionicons;
  /* font-size: 1em; */
}

.fork:before {
  content: "\f25e";
  font-family: ionicons;
  /* font-size: 1em; */
}

.join:before {
  content: "\f267";
  font-family: ionicons;
  /* font-size: 1em; */
}

.subflow:before {
  content: "\f40a";
  font-family: ionicons;
  /* font-size: 1em; */
}
.dispatch::before {
   content: "\f40a";
  font-family: ionicons;
}
.distribute::before {
   content: "\f40a";
  font-family: ionicons;
}
</style>
